www.gusucode.com > 有监督的 CNN 网络完成对MNIST 数字的识别 > 有监督的 CNN 网络完成对MNIST 数字的识别/CNN—卷积神经网络数字识别/cnet_tool.m

    function varargout = cnet_tool(varargin)
% 更方便将MNIST数据文件中(t10k-images-idx3-ubyte、
% t10k-labels-idx1-ubyte train-images-idx3-ubyte
% 和train-labels-idx1-ubyte)读取出来,
% 所以演示可以自动找到他们。
% 2014-12-12

mInputArgs      =   varargin;   % 变长度输入宗量,调用GUI(Graphical User Interface 图形用户界面)时命令行参数
mOutputArgs     =   {};         % 变量用于存储输出当GUI返回
mIconCData      =   [];         % 用CData的图标编辑这个GUI的维度
                                % (mIconHeight,mIconWidth,3)
mIsEditingIcon  =   false;      % 标记显示当前鼠标移动是否用于编辑颜色
                                % 变量支持自定义属性/值配对

mPropertyDefs   =   {...        % 支持自定义属性/值配对的GUI
                     'iconwidth',   @localValidateInput, 'mIconWidth';
                     'iconheight',  @localValidateInput, 'mIconHeight';
                     'MNISTfile',   @localValidateInput, 'mMNISTFile'};
mIconWidth      =   28;         % 通过使用输入属性来初始化“iconwidth”
mIconHeight     =   28;         % 通过使用输入属性来初始化“iconheight”
% 
% 
mMNISTFile      =   './MNIST/t10k-images-idx3-ubyte'; %格式满足(根目录,'./'); 
% 
% 
Images = {0};
im_ptr = 1;
autorecognition =   false;
tmp             =   load('cnet.mat');
cnet            =   tmp.sinet;

% %在这个GUI上创建所有UI对象,这样可以在这个GUI用对应的函数
hMainFigure     =   figure(...
                    'Units','characters',...
                    'MenuBar','none',...
                    'Toolbar','none',...
                    'Position',[71.8 34.7 106 36.15],...
                    'WindowStyle', 'normal',...
                    'WindowButtonDownFcn', @hMainFigureWindowButtonDownFcn,...
                    'WindowButtonUpFcn', @hMainFigureWindowButtonUpFcn,...
                    'WindowButtonMotionFcn', @hMainFigureWindowButtonMotionFcn);
hIconEditPanel  =    uipanel(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Clipping','on',...
                    'Position',[1.8 4.3 68.2 27.77]);
hIconEditAxes   =   axes(...
                    'Parent',hIconEditPanel,...
                    'vis','off',...
                    'Units','characters',...
                    'Position',[2 1.15 64 24.6]);
hIconFileText   =   uicontrol(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'HorizontalAlignment','left',...
                    'Position',[3.8 32.9 16.2 1.46],...
                    'String','MNIST 文件夹: ',...
                    'Style','text');
hIconFileEdit   =   uicontrol(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'HorizontalAlignment','left',...
                    'Position',[19.8 32.9 78.2 1.62],...
                    'String','创建一个新的图标或键入一个图标图像文件进行编辑',...
                    'Enable','inactive',...
                    'Style','edit',...
                    'ButtondownFcn',@hIconFileEditButtondownFcn,...
                    'Callback',@hIconFileEditCallback);
hIconFileButton =   uicontrol(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Callback',@hIconFileButtonCallback,...
                    'Position',[98 32.85 5.8 1.77],...
                    'String','...',...
                    'TooltipString','Import From Image File');
hPreviewPanel   =   uipanel(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Title','预览',...
                    'Clipping','on',...
                    'Position',[71.8 19.15 32.2 13]);
hPreviewControl =   uicontrol(...
                    'Parent',hPreviewPanel,...
                    'Units','characters',...
                    'Enable','inactive',...
                    'Visible','off',...
                    'Position',[2 3.77 16.2 5.46],...
                    'String','');
hPrevDigitButton =   uicontrol(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Position',[80 20 5 2],...
                    'String','<',...
                    'Callback',@hPrevDigitButtonCallback);

hNextDigitButton =   uicontrol(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Position',[91.7 20 5 2],...
                    'String','>',...
                    'Callback',@hNextDigitButtonCallback);

hAutorecognitionCheck = uicontrol(...
                    'Parent', hMainFigure,...
                    'Units', 'characters',...
                    'HorizontalAlignment', 'left',...
                    'Position', [71.8 17.6 32.2 1],...
                    'String','自动识别',...
                    'Style','CheckBox', ...
                    'Callback',@hAutorecognitionCheckCallback, ...
                    'Value', 0);
                
hResultPanel   =    uipanel(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Title','识别结果显示',...
                    'Clipping','on',...
                    'Position',[71.8 4.3 32.2 13]);
hResultText =   uicontrol(...
                    'Parent',hResultPanel,...
                    'Units','normalized',...
                    'Style','text', ...
                    'Enable','inactive',...
                    'Visible','on',...
                    'FontSize', 50, ...
                    'Position',[.2 .2 .6 .6],...
                    'String','');
for i = 0:9,
    hResultDigits(1+i) = uicontrol(...
        'Parent',hResultPanel,...
        'Units','normalized',...
        'Enable','inactive',...
        'Style','text', ...
        'FontSize', 14, ...
        'Position',[.02+i*.095 .05 .09 .128],...
        'String', char('0'+i), ...
        'ForegroundColor', [1 1 1]);
end
                
hSectionLine    =   uipanel(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'HighlightColor',[0 0 0],...
                    'BorderType','line',...
                    'Title','',...
                    'Clipping','on',...
                    'Position',[2 3.62 102.4 0.077]);
hOKButton       =   uicontrol(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Position',[65.8 0.62 17.8 2.38],...
                    'String','确定',...
                    'Callback',@hOKButtonCallback);
hCancelButton   =   uicontrol(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Position',[85.8 0.62 17.8 2.38],...
                    'String','取消',...
                    'Callback',@hCancelButtonCallback);
hRecognizeButton   =   uicontrol(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Position',[10.0 0.62 17.8 2.38],...
                    'String','识别',...
                    'Callback',@hRecognizeButtonCallback);
hClearButton   =   uicontrol(...
                    'Parent',hMainFigure,...
                    'Units','characters',...
                    'Position',[30.0 0.62 17.8 2.38],...
                    'String','清除',...
                    'Callback',@hClearButtonCallback);
                
% host ColorPalette PaletteContainer和保持功能,处理让其选择颜色编辑图标


% 改变所需的合适的外观和运行在不同的平台上
prepareLayout(hMainFigure);                            

% 当调用GUI时提供处理输入参数的命令行
processUserInputs();                            

% 初始化iconEditor,使用默认或自定义的数据通过属性/值对
localUpdateIconPlot();

% 使GUI出现在屏幕上
set(hMainFigure,'visible', 'on');
movegui(hMainFigure,'onscreen');

% 使GUI阻塞(blocking)
uiwait(hMainFigure);

% 如果请求,返回编辑图标CData
mOutputArgs{1} =mIconCData;
if nargout>0
    [varargout{1:nargout}] = mOutputArgs{:};
end

    %------------------------------------------------------------------
    function hMainFigureWindowButtonDownFcn(hObject, eventdata)
%鼠标在图上被按下时调用。
%用来改变特定的图标的颜色数据点下鼠标的当前选中colorPalette的颜色
        if (ancestor(gco,'axes') == hIconEditAxes)
            mIsEditingIcon = true;
            localEditColor();
        end
    end

    %------------------------------------------------------------------
    function hMainFigureWindowButtonUpFcn(hObject, eventdata)
    % 释放窗口当鼠标点击退出编辑模式的图标
        mIsEditingIcon = false;
    end

    %------------------------------------------------------------------
    function hMainFigureWindowButtonMotionFcn(hObject, eventdata)
    %回调时调用鼠标移动,这样可以更新图标颜色数据的编辑模式
        if (ancestor(gco,'axes') == hIconEditAxes)
            localEditColor();
        end
    end

    %------------------------------------------------------------------
    function hIconFileEditCallback(hObject, eventdata)
    % %的回调时调用用户改变了图标文件名称的图标可以加载
        file = get(hObject,'String');
        if exist(file, 'file') ~= 2
            errordlg(['The given icon file cannot be found ' 10, file], ...
                    'Invalid Icon File', 'modal');
            set(hObject, 'String', mMNISTFile);
        else
            mIconCData = [];
            localUpdateIconPlot();            
        end
    end

    %------------------------------------------------------------------
    function hIconFileEditButtondownFcn(hObject, eventdata)
    %调称用户第一次按下鼠标的editbox图标文件
        set(hObject,'String','');
        set(hObject,'Enable','on');
        set(hObject,'ButtonDownFcn',[]);        
        uicontrol(hObject);
    end

    %------------------------------------------------------------------
    function hOKButtonCallback(hObject, eventdata)
    % OK按钮被按下时调用
        uiresume;
        delete(hMainFigure);
    end

    %------------------------------------------------------------------
    function hCancelButtonCallback(hObject, eventdata)
    % 取消按钮被按下时调用
        mIconCData =[];
        uiresume;
        delete(hMainFigure);
    end
    %------------------------------------------------------------------
    function hRecognizeButtonCallback(hObject, eventdata)
        Ip = preproc_image(mIconCData);
        [out cnet] = sim(cnet, Ip);
        max_out = max(out);
        for out_i = 1:numel(out),
            set(hResultDigits(out_i), 'ForegroundColor', [1 1 1]*(1.8-out(out_i))/3.6)
        end
        digit = find(out == max_out, 1) - 1;
        if ~isempty(digit),
            set(hResultText, 'string', char('0'+digit), 'ForegroundColor', [1 1 1]*(1.8-max_out)/3.6)
        end
        
    end
    %------------------------------------------------------------------
    function hClearButtonCallback(hObject, eventdata)
        mIconCData = ones(mIconHeight, mIconWidth, 3);
        localUpdateIconPlot();
        if autorecognition,
            hRecognizeButtonCallback(hObject, eventdata)
        end
    end
    %------------------------------------------------------------------
    function hAutorecognitionCheckCallback(hObject, eventdata)
        autorecognition = get(hAutorecognitionCheck, 'Value');
        if autorecognition,
            hRecognizeButtonCallback(hObject, eventdata)
        end

    end
    %------------------------------------------------------------------
    function hIconFileButtonCallback(hObject, eventdata)
    %回调时调用的图标文件选择按钮被按下
        filespec = {'*.*', 'Database file '};
        [filename, pathname] = uigetfile(filespec, 'Pick an database file', mMNISTFile);

        if ~isequal(filename,0)
            mMNISTFile = fullfile(pathname, filename);             
            set(hIconFileEdit, 'ButtonDownFcn',[]);            
            set(hIconFileEdit, 'Enable','on');            
            
            mIconCData = [];
            localUpdateIconPlot();            
            
        elseif isempty(mIconCData)
            set(hPreviewControl,'Visible', 'off');            
        end
    end

    function hPrevDigitButtonCallback(hObject, eventdata)
        if(im_ptr>1)
            im_ptr=im_ptr-1;
        end
        im = abs(double(Images{im_ptr})/255-1)';
        mIconCData = cat(3,im,im,im);   
        localUpdateIconPlot();
        if autorecognition,
            hRecognizeButtonCallback(hObject, eventdata)
        end        
    end

    function hNextDigitButtonCallback(hObject, eventdata)
        if(im_ptr<numel(Images))
            im_ptr=im_ptr+1;
        end
        im = abs(double(Images{im_ptr})/255-1)';
        mIconCData = cat(3,im,im,im);    
        localUpdateIconPlot();
        if autorecognition,
            hRecognizeButtonCallback(hObject, eventdata)
        end
    end
    %------------------------------------------------------------------
    function localEditColor
   % helper函数改变一个图标的颜色数据点在colorPalette当前选中的颜色 
        if mIsEditingIcon
            pt = get(hIconEditAxes,'currentpoint');

            x = max(1, min(ceil(pt(1,1)), mIconWidth));
            y = max(1, min(ceil(pt(1,2)), mIconHeight));

            % 更新颜色选择
            m = get(gcf,'SelectionType');
            if m(1) == 'n', % 左按钮按下
                mIconCData(y, x,:) = 0;
                if y<mIconHeight,   mIconCData(y+1,x,:) = .8*mIconCData(y+1,x,:); end
                if x<mIconWidth,    mIconCData(y,x+1,:) = .8*mIconCData(y,x+1,:); end
                if y>1,             mIconCData(y-1,x,:) = .8*mIconCData(y-1,x,:); end
                if x>1,             mIconCData(y,x-1,:) = .8*mIconCData(y,x-1,:); end
            else
                mIconCData(y, x,:) = 1;
            end
            localUpdateIconPlot();
        end
    end

    %------------------------------------------------------------------
    function localUpdateIconPlot   
   % 时更新iconEditor helper函数图标数据更改
   % 初始化图标CData如果没有初始化
        if isempty(mIconCData)
            if exist(mMNISTFile, 'file') == 2
                try
                    Images = readMNIST_image(mMNISTFile,1000);
                    %im_ptr = 1;
                    im = abs(double(Images{im_ptr})/255-1)';
                    mIconCData = cat(3,im,im,im);
                    set(hIconFileEdit, 'String', mMNISTFile);            
                catch
                    errordlg(['Could not load MNIST database file successfully. ',...
                              'Make sure the file name is correct: ' mMNISTFile],...
                              'Invalid MNIST File', 'modal');
                    mIconCData = nan(mIconHeight, mIconWidth, 3);
                end
            else 
                mIconCData = nan(mIconHeight, mIconWidth, 3);
            end
        end
        
        % 更新预览控件
        rows = size(mIconCData, 1);
        cols = size(mIconCData, 2);
        previewSize = getpixelposition(hPreviewPanel);
        % 标题
        previewSize(4) = previewSize(4) -15;
        controlWidth = previewSize(3);
        controlHeight = previewSize(4);  
        controlMargin = 6;
        if rows+controlMargin<controlHeight
            controlHeight = rows+controlMargin;
        end
        if cols+controlMargin<controlWidth
            controlWidth = cols+controlMargin;
        end        
        setpixelposition(hPreviewControl,[(previewSize(3)-controlWidth)/2,(previewSize(4)-controlHeight)/2, controlWidth, controlHeight]); 
        set(hPreviewControl,'CData', mIconCData,'Visible','on');
        
        % 更新 图标编辑窗格
        set(hIconEditPanel, 'Title',['图标编辑窗格 (', num2str(rows),' X ', num2str(cols),')']);
        
        s = findobj(hIconEditPanel,'type','surface');        
        if isempty(s)
            gridColor = get(0, 'defaultuicontrolbackgroundcolor') - 0.2;
            gridColor(gridColor<0)=0;
            s=surface('edgecolor',gridColor,'parent',hIconEditAxes);
        end        
        % 设置xdata、ydata zdata以防行和/或关口的变化
        set(s,'xdata',0:cols,'ydata',0:rows,'zdata',zeros(rows+1,cols+1),'cdata',localGetIconCDataWithNaNs());

        set(hIconEditAxes,'drawmode','fast','xlim',[-.5 cols+.5],'ylim',[-.5 rows+.5]);
        axis(hIconEditAxes, 'ij', 'off');        
    end

    %------------------------------------------------------------------
	function cdwithnan = localGetIconCDataWithNaNs()
		% 增加非数值(NaN)的边缘mIconCData将整个图标呈现在图窗格中。这是必要的,因为表面的行为。
		cdwithnan = mIconCData;
		cdwithnan(:,end+1,:) = NaN;
		cdwithnan(end+1,:,:) = NaN;
		
	end

    %------------------------------------------------------------------
    function processUserInputs
    % helper函数,处理输入属性/值对
    % 应用可能的图和可辨认的自定义属性/值对
        for index=1:2:length(mInputArgs)
            if length(mInputArgs) < index+1
                break;
            end
            match = find(ismember({mPropertyDefs{:,1}},mInputArgs{index}));
            if ~isempty(match)  
               % 验证输入,并将其分配给一个变量
               if ~isempty(mPropertyDefs{match,3}) && mPropertyDefs{match,2}(mPropertyDefs{match,1}, mInputArgs{index+1})
                   assignin('caller', mPropertyDefs{match,3}, mInputArgs{index+1}) 
               end
            else
                try 
                    set(topContainer, mInputArgs{index}, mInputArgs{index+1});
                catch
                    % 如果这不是一个有效的图属性值对,让两个去到下一个
                    continue;
                end
            end
        end        
    end

    %------------------------------------------------------------------
    function isValid = localValidateInput(property, value)
    % helper函数来验证用户提供输入属性/值对。你可以在这里选择显示警告或错误。
        isValid = false;
        switch lower(property)
            case {'iconwidth', 'iconheight'}
                if isnumeric(value) && value >0
                    isValid = true;
                end
            case 'MNISTfile'
                if exist(value,'file')==2
                    isValid = true;                    
                end
        end
    end
end % iconEditor结束

%------------------------------------------------------------------
function prepareLayout(topContainer)
%这个效用函数负责相关问题的外观和运行在多个平台上。
%可以重用该函数在其他gui或修改它以适合你的需要。
    allObjects = findall(topContainer);
    warning off  %临时报告修复
    try
        titles=get(allObjects(isprop(allObjects,'TitleHandle')), 'TitleHandle');
        allObjects(ismember(allObjects,[titles{:}])) = [];
    catch
    end
    warning on

    % 使用这个GUI文件的名称作为标题的数字
    defaultColor = get(0, 'defaultuicontrolbackgroundcolor');
    if isa(handle(topContainer),'figure')
        set(topContainer,'Name', mfilename, 'NumberTitle','off');
        % 使GUI对象的图颜色匹配
        set(topContainer, 'Color',defaultColor);
    end

    % 使GUI对象可用于回调,这样他们不能改变意外其他MATLAB命令
    set(allObjects(isprop(allObjects,'HandleVisibility')), 'HandleVisibility', 'Callback');

    % 使GUI的正常运行在多个平台上使用合适的单位
    if strcmpi(get(topContainer, 'Resize'),'on')
        set(allObjects(isprop(allObjects,'Units')),'Units','Normalized');
    else
        set(allObjects(isprop(allObjects,'Units')),'Units','Characters');
    end
%你可能想要修改editbox,popupmenu上默认的颜色,在Windows上列表框白色
    
    if ispc
        candidates = [findobj(allObjects, 'Style','Popupmenu'),...
                           findobj(allObjects, 'Style','Edit'),...
                           findobj(allObjects, 'Style','Listbox')];
        set(findobj(candidates,'BackgroundColor', defaultColor), 'BackgroundColor','white');
    end
end
function out = preproc_image(id)
    %图像预处理
    Inorm = id(:,:,1);
    Inorm(~isfinite(Inorm)) = 1;
    Inorm = abs(Inorm-1)';
    out = zeros(32);
    out(3:30,3:30) = Inorm;
    if sum(out(:))>0,
        gain = 1./ std(out(:));
        out = (out - mean(out(:))).*gain;        
    end
end
function I = readMNIST_image(filepath,num)
%读MNIST_image MNIST handwriten阅读图像数据库。读取只有图片没有标签,指定文件名
%
%的语法
%
% I = readMNIST_image(filepath num)
%
%的描述
%的输入:
% filepath——名称数据库文件的路径
% n -图像处理的数量
%输出:
% I - 28 x28训练图像大小的单元阵列
% = = = = = = = = = = =加载训练集

    fid = fopen(filepath,'r','b');  %大端法(二进位资料次序)
    magicNum = fread(fid,1,'int32');    %幻数
    if(magicNum~=2051) 
        display('Error: cant find magic number');
        return;
    end
    imgNum = fread(fid,1,'int32');  %图片的数量
    rowSz = fread(fid,1,'int32');   %图片的高度
    colSz = fread(fid,1,'int32');   %图片的宽度

    if(num<imgNum) 
        imgNum=num; 
    end

    for k=1:imgNum
        I{k} = uint8(fread(fid,[rowSz colSz],'uchar'));
    end
    fclose(fid);
end